import datetime
import random
import re

from flask import request, abort, make_response, current_app, jsonify, session

from info import redis_store, db
from info import constants
from info.lib.yuntongxun.sms import CCP
from info.models import User
from info.response_code import RET
from . import passport_bp
from info.utils.captcha.captcha import captcha


# 3. 使用蓝图对象装饰视图函数
# 用户退出登录
# /passport/quit_login
@passport_bp.route('/quit_login', methods=['POST'])
def quit_login():
    # 1. 参数获取
    # 2. 参数校检
    # 3. 业务逻辑
    session.pop('user_id', '')
    session.pop('mobile', '')
    session.pop('nick_name', '')
    # 4. 返回数据
    return jsonify(errno=RET.OK, errmsg='用户退出登录成功')


# 用户登录模块后端实现
# /passport/user_login
@passport_bp.route('/user_login', methods=['POST'])
def user_login():
    # 1. 获取参数
    user_login = request.json
    moblie = user_login.get('moblie', '')
    password = user_login.get('password', '')
    # print(moblie, password)
    # 2. 参数校检
    if not all([moblie, password]):
        current_app.logger.error('参数不足')
        return jsonify(errno=RET.PARAMERR, errmsg='参数不足')
    # 验证手机号格式是否正确
    if not re.match(r'1[3478][0-9]{9}', moblie):
        current_app.logger.error('手机号格式不正确')
        return jsonify(errno=RET.PARAMERR, errmsg='手机号格式不正确')
    # 3. 业务逻辑
    # 验证用户是否已注册
    try:
        user = User.query.filter(User.mobile == moblie).first()
    except Exception as e:
        current_app.logger.error("数据库查询异常")
        return jsonify(errno=RET.DBERR, errmsg='数据库查询异常')
    
    if not user:
        current_app.logger.error("用户未注册")
        return jsonify(errno=RET.USERERR, errmsg='用户未注册')
    # 验证用户密码是否正确
    if user.check_passowrd(password) is False:
        return jsonify(errno=RET.PWDERR, errmsg='密码输入不正确')
    
    # 更新用户最后一次登录的时间
    user.update_time = datetime.datetime.now()
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error('登录数据提交错误')
        # 数据库回滚
        db.session.rollback()
        return jsonify(erron=RET.LOGINERR, errmsg='用户登录失败')
    
    # 将用户信息保存到session中, 保持用户登录状态
    session['user_id'] = user.id
    session['mobile'] = user.mobile
    session['nick_name'] = user.nick_name
    # 4. 返回数据
    return jsonify(errno=RET.OK, errmsg='登录成功')
    

# 用户注册后端实现
# /passport/register
@passport_bp.route('/register', methods=['POST'])
def register():
    # 1. 接收请求参数
    register_dict = request.json
    moblie = register_dict['moblie']
    sms_code = register_dict['sms_code']
    password = register_dict['password']
    # 2. 参数校检
    if not all([moblie, sms_code, password]):
        current_app.logger.error('参数不足')
        return jsonify(errno=RET.PARAMERR, errmsg="参数不足")
    # 手机号格式是否合法
    if not re.match(r'1[3578][0-9]{9}', moblie):
        current_app.logger.error('手机号格式不合法')
        return jsonify(errno=RET.DATAERR, errmsg="手机号格式不合法")
    # 3. 业务逻辑
    # 取出redis中真实的短信验证码与用户输入的短信验证码进行对比
    try:
        real_sms_code = redis_store.get("SMS_CODE_%s" % moblie)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询redis中短信验证码异常")
    
    # 判断短信验证码是否失效
    if not real_sms_code:
        current_app.logger.error('短信验证码失效')
        return jsonify(errno=RET.NODATA, errmsg="短信验证码失效")
    
    # 判断用户输入的短信验证码是否正确
    if real_sms_code != sms_code:
        # 不正确, 返回短信验证码输入错误
        current_app.logger.error('用户短信验证码输入错误')
        return jsonify(erron=RET.DATAERR, errmsg='用户短信验证码输入错误')
    # 正确,将用户信息保存到mysql数据库中
    user = User()
    user.nick_name = moblie
    user.mobile = moblie
    user.password = password
    user.last_login = datetime.datetime.now()
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error("数据库写入错误")
        # 数据库回滚
        db.session.rollback()
        return jsonify(errno=RET.DATAERR, errmsg="数据库写入错误")
    
    # 并将用户信息保存到session中,注册表示登录成功, 提高用户体验
    session['user_id'] = user.id
    session['nick_name'] = user.nick_name
    session['mobile'] = user.mobile
    # 4. 返回数据
    return jsonify(errno=RET.OK, errmsg="注册成功")


# 短信验证码验证
# /passport/sms_code
@passport_bp.route('/sms_code', methods=['POST'])
def get_sms_code():
    """短信验证码后端实现"""
    """
    1. 接受请求参数
    2. 参数校检, mobile, image_code, image_code_id是否有空值
    3. 业务逻辑
        3.1 判断 moblie 手机号是否合法
            3.1.1 判断手机号是否被注册
                若已被注册, 返回手机号已被注册
        3.2 使用image_code_id从redis数据库中取出image_code值, 判空
            若为空, 返回验证码过期
        若有值, 将image_code从redis数据库中删除
        3.3 将从数据库中取出的值与image_code比较, 统一转化为小写进行比较
            若不相等, 返回图片验证码输入错误
        3.4 生成随机验证码
            通过第三方模块向用户发送验证短信
                若发送失败, 返回 短信验证码发送失败
            发送成功, 将短信验证码存储到redis数据库中
    4. 返回数据
        ok  短信发送成功
        
    """

    # 1. 接受请求参数
    param_dict = request.json
    moblie = param_dict["moblie"]
    image_code = param_dict["image_code"]
    image_code_id = param_dict["image_code_id"]
    
    # 2. 参数校检
    if not all([moblie, image_code, image_code_id]):
        # 参数不足
        current_app.logger.error("参数不足")
        # 返回错误信息
        err_dict = {"errno": RET.PARAMERR, "errmsg": "参数不足"}
        return jsonify(err_dict)
    
    # 3. 判断 moblie 手机号是否合法
    if not re.match(r'1[3578][0-9]{9}', moblie):
        return jsonify(errno=RET.PARAMERR, errmsg="手机号码格式错误")
    try:
        user = User.query.filter(User.mobile == moblie).first()
        # print(user)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询用户数据异常")
    if user:
        return jsonify(errno=RET.DATAERR, errmsg="手机号已被注册")
    
    # 获取redis数据库中的真实的图片验证码
    try:
        real_image_code = redis_store.get("Iamge_Code_%s" % image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询redis图形验证码异常")
    # 判断图片验证码是否为空, 为空 返回图片验证码过期
    if not real_image_code:
        return jsonify(errno=RET.NODATA, errmsg="图形验证码过期了")
    # 不为空, 删除redis数据库中的验证码, 比较用户输入的验证码与真实验证码,判断用户输入是否正确
    redis_store.delete("Iamge_Code_%s" % image_code_id)
    if image_code.lower() != real_image_code.lower():
        return jsonify(errno=RET.DATAERR, errmsg="图形验证码填写错误")
    
    # 用户输入正确, 生成短信验证码, 并发送给浏览器
    real_sms_code = random.randint(0, 999999)
    real_sms_code = "%06d" % real_sms_code
    try:
        result = CCP().send_template_sms(moblie, [real_sms_code, 5], 1)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg="云通信发送短信验证码异常")
    if result == -1:
        return jsonify(errno=RET.THIRDERR, errmsg="云通信发送短信验证码异常")
    # 将短信验证码存储到redis数据库中
    redis_store.setex("SMS_CODE_%s" % moblie, constants.SMS_CODE_REDIS_EXPIRES, real_sms_code)
    
    return jsonify(errno=RET.OK, errmsg="发送短信验证码成功")
    

# 图片验证码验证
# /passport/image_code
@passport_bp.route('/image_code')
def get_image_code():
    """生成图片验证码的后端接口"""
    
    # 1. 接受请求参数
    code_id = request.args.get("code_id", '')
    # 2. 参数校验
    if not code_id:
        return abort(404)
    # 3. 业务逻辑
    #   3.1 调用工具类生成验证码图片， 验证码真实值
    image_name, real_image_code, image_data = captcha.generate_captcha()
    #   3.2 UUID 作为key，将真实验证码保存到redis数据库中， 设置有效时间 90 秒
    redis_store.setex("Iamge_Code_%s" % code_id, constants.IMAGE_CODE_REDIS_EXPIRES, real_image_code)
    # 4. 发送数据： 将图片验证码发送给客户端
    response = make_response(image_data)
    response.headers['Content-Type'] = 'image/png'
    return response



